package com.leo.foodmaster.commons.config.security;

import cn.hutool.core.util.ReUtil;
import com.leo.foodmaster.commons.annotation.Inner;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;

/**
 * <p>
 * 资源服务器对外直接暴露URL,如果设置context-path 要特殊处理
 * </p>
 *
 * @author ：Leo
 * @since ：2021-05-12 9:53
 */
@Slf4j
@Component
@ConfigurationProperties(prefix = "whitelist")
public class PermitAllUrlProperties implements InitializingBean {
	private static final Pattern PATTERN = Pattern.compile("\\{(.*?)}");
	private static final String ASTERISK = "*";
	@Resource
	private WebApplicationContext applicationContext;

	@Setter
	private List<String> ignoreUrls = new ArrayList<>();

	public String[] getIgnoreUrls() {
		return ignoreUrls.toArray(new String[0]);
	}

	@Override
	public void afterPropertiesSet() {
		log.info("将带有@Inner注解的接口放入白名单。。。");
		RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
		Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();

		map.keySet().forEach(info -> {
			HandlerMethod handlerMethod = map.get(info);

			// 获取方法上边的注解 替代path variable 为 *
			// 把有@Inner注解的接口的url添加到白名单中
			Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class);
			Optional.ofNullable(method).ifPresent(inner -> {
				assert info.getPatternsCondition() != null;
				info.getPatternsCondition().getPatterns()
						.forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, ASTERISK)));
			});

			// 获取类上边的注解, 替代path variable 为 *
			// 把有@Inner注解的类的url加入到白名单中
			Inner controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Inner.class);
			Optional.ofNullable(controller).ifPresent(inner -> {
				assert info.getPatternsCondition() != null;
				info.getPatternsCondition().getPatterns()
						.forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, ASTERISK)));
			});
		});
	}

}
